﻿namespace net.zxteam.zxlang.Lexer.DynamicParser
{
	using System;
	using System.Collections.Generic;

	public sealed class StringParsingSource : IParsingSource
	{
		private readonly Stack<StateScope> _stateStack = new Stack<StateScope>();
		private readonly string _text;
		private int _position;

		public StringParsingSource(string text)
		{
			if (text == null) throw new ArgumentNullException();

			this._text = text;
		}

		public char ReadChar()
		{
			if (!this.HasChars) throw new InvalidOperationException();

			return _text[_position++];
		}

		public bool HasChars { get { return _position < _text.Length; } }

		public int Position { get { return _position; } }


		public IStateScope CreateStateScope()
		{
			var state = new StateScope(this, _position);
			_stateStack.Push(state);
			return state;
		}

		private void CommitState(StateScope ss)
		{
			StateScope item = _stateStack.Peek();
			if (ss != item) throw new InvalidOperationException();
			_stateStack.Pop();
		}

		private void RollbackState(StateScope ss)
		{
			StateScope item = _stateStack.Peek();
			if (ss != item) throw new InvalidOperationException();
			_stateStack.Pop();
			_position = item.Position;
		}

		private class StateScope : IStateScope
		{
			private readonly StringParsingSource _owner;
			public readonly int Position;
			private bool _wasCommited;

			int IStateScope.Position { get { return this.Position; } }

			public StateScope(StringParsingSource owner, int pos) { this._owner = owner; this.Position = pos; }
			public void Commit() { _wasCommited = true; _owner.CommitState(this); }
			public void Dispose() { if (!_wasCommited) _owner.RollbackState(this); }
		}

		public void Dispose() { }
	}
}
